package com.lanyou.esb.cook.proxy.service.impl;

import java.util.Date;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;

import com.lanyou.esb.cook.proxy.common.Constants;
import com.lanyou.esb.cook.proxy.common.SystemResCode;
import com.lanyou.esb.cook.proxy.common.DateUtils;
import com.lanyou.esb.cook.proxy.common.ParamFactory;
import com.lanyou.esb.cook.proxy.entity.Http;
import com.lanyou.esb.cook.proxy.entity.Token;
import com.lanyou.esb.cook.proxy.entity.ParamSet;
import com.lanyou.esb.cook.proxy.exception.AuthException;
import com.lanyou.esb.cook.proxy.meta.EnableType;
import com.lanyou.esb.cook.proxy.meta.Environment;
import com.lanyou.esb.cook.proxy.service.AuthService;
import com.lanyou.esb.cook.proxy.service.TokenService;

/**
 * 授权服务
 * 
 * @author Davey.wu
 */
public class AuthServiceImpl implements AuthService {
	/** 令牌服务接口 **/
	private TokenService tokenService;

	@Override
	public Token getToken(String systemCode, String callSystemCode, Http http,
			Environment environment) throws Exception {
		switch (environment) {
		case PRODUCTION:
			// 正式环境
			return tokenService.getToken(systemCode, http.getCode(),
					http.getVersion(), callSystemCode);
		case TEST:
			// 测试环境
			return tokenService.getTestToken(systemCode, http.getCode(),
					http.getVersion(), callSystemCode);
		default:
			// 没有指定环境，返回空值
			return null;
		}

	}

	@Override
	public Token authenticate(String applyKey, String systemCode,
			String ifCode, String ifVersion, Environment environment)
			throws Exception {
		switch (environment) {
		case PRODUCTION:
			// 正式环境
			return authenticate(applyKey, systemCode, ifCode, ifVersion);
		case TEST:
			// 测试环境
			return authenticate4ServiceTest(applyKey, systemCode, ifCode,
					ifVersion);
		default:
			// 没有指定环境，返回空值
			return null;
		}

	}

	@Override
	public String generateAccessToken() {
		// 生成访问令牌
		return UUID.randomUUID().toString().replace("-", "");
	}

	@Override
	public int getApplyUpperLimit() {
		ParamSet paramSet = ParamFactory
				.getParamSet(Constants.ACCESSTOKEN_DAY_APP_UPPER_LIMIT);
		int result = Constants.ACCESSTOKEN_DAY_APP_UPPER_LIMIT_DEFAULT;
		if (paramSet != null && StringUtils.isNotBlank(paramSet.getValue())) {
			try {
				result = Integer.parseInt(paramSet.getValue());
			} catch (Exception e) {
				result = Constants.ACCESSTOKEN_DAY_APP_UPPER_LIMIT_DEFAULT;
			}
		}
		return result;
	}

	@Override
	public int getExpiresIn() {
		ParamSet paramSet = ParamFactory
				.getParamSet(Constants.ACCESSTOKEN_EXPIRES_IN);
		int result = Constants.ACCESSTOKEN_EXPIRES_IN_DEFAULT;
		if (paramSet != null && StringUtils.isNotBlank(paramSet.getValue())) {
			try {
				result = Integer.parseInt(paramSet.getValue());
			} catch (Exception e) {
				result = Constants.ACCESSTOKEN_EXPIRES_IN_DEFAULT;
			}
		}
		return result;
	}

	/**
	 * 服务测试模式下授权
	 * 
	 * @param applyKey
	 *            ：密钥
	 * @param systemCode
	 *            ：系统编码
	 * @param ifCode
	 *            ：接口编码
	 * @param ifVersion
	 *            ：接口版本
	 * @return
	 * @throws Exception
	 */
	private Token authenticate4ServiceTest(String applyKey, String systemCode,
			String ifCode, String ifVersion) throws Exception {
		// 获取令牌
		Token token = tokenService.getToken4Acc(applyKey, systemCode, ifCode,
				ifVersion);
		// 找不到令牌信息，抛出异常
		if (token == null) {
			throw new AuthException(SystemResCode.MSG_TOKEN_INFO_ILLEGAL,
					SystemResCode.CODE_TOKEN_INFO_ILLEGAL);
		}
		// 生成访问令牌
		String accessToken = generateAccessToken();
		// 获取令牌有效期
		int expiresIn = getExpiresIn();
		// 更新访问令牌
		token.updateToken(accessToken, expiresIn);
		// 更新测试令牌
		return this.tokenService.updateTestToken(token);
	}

	/**
	 * 授权
	 * 
	 * @param applyKey
	 *            ：密钥
	 * @param systemCode
	 *            ：系统编码
	 * @param ifCode
	 *            ：接口编码
	 * @param ifVersion
	 *            ：接口版本
	 * @return
	 * @throws Exception
	 */
	private Token authenticate(String applyKey, String systemCode,
			String ifCode, String ifVersion) throws Exception {
		// 获取令牌
		Token token = tokenService.getToken4Acc(applyKey, systemCode, ifCode,
				ifVersion);
		// 校验令牌
		validate(token);
		// 生成访问令牌
		String accessToken = generateAccessToken();
		// 获取令牌有效期
		int expiresIn = getExpiresIn();
		// 更新访问令牌
		token.updateToken(accessToken, expiresIn);
		// 更新令牌
		return this.tokenService.updateToken(token);
	}

	/**
	 * 校验令牌信息是否符合授权规则
	 * 
	 * @param token
	 * @throws AuthException
	 */
	private void validate(Token token) throws AuthException {
		if (token == null) {
			throw new AuthException(SystemResCode.MSG_TOKEN_INFO_ILLEGAL,
					SystemResCode.CODE_TOKEN_INFO_ILLEGAL);
		}
		// 令牌不可用
		if (!EnableType.ENABLE.ValueCode.equals(token.getIsEnable())) {
			throw new AuthException(SystemResCode.MSG_TOKEN_DISABLE,
					SystemResCode.CODE_TOKEN_DISABLE);
		}
		// 密钥过期时间为空
		if (token.getKeyInvalidDate() == null) {
			throw new AuthException(SystemResCode.MSG_APPLYKEY_EXPIRESIN_EMPTY,
					SystemResCode.CODE_APPLYKEY_EXPIRESIN_EMPTY);
		}
		// 令牌生成生成时间为空,说明还没有令牌，可以申请
		if (token.getApplyDate() == null) {
			return;
		}
		Date today = new Date();
		// 上次申请与本次申请不是同一天，可以申请
		if (!DateUtils.isSameDay(token.getApplyDate(), today)) {
			return;
		}
		// 获取当前已申请次数
		int applyTimes = token.getCurApplyQty();
		// 获取每日申请上限
		int limit = getApplyUpperLimit();
		// 上限为0，默认为无上限
		if (limit == 0) {
			return;
		}
		// 判断是否已达上限
		if (applyTimes >= limit) {
			throw new AuthException(SystemResCode.MSG_OVER_MAX_APPLYTIMES,
					SystemResCode.CODE_OVER_MAX_APPLYTIMES);
		}
	}

	public TokenService getTokenService() {
		return tokenService;
	}

	public void setTokenService(TokenService tokenService) {
		this.tokenService = tokenService;
	}
}
